/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 *
 */

import path from 'path';

import { hvigorCore, TaskDetails } from '@ohos/hvigor';
import fse from 'fs-extra';

import { CmakeUtil } from '../../utils/cmake-util.js';
import { HarTargetUtil } from '../../utils/har-target-util.js';
import { HspTargetUtils } from '../../utils/hsp-target-utils.js';
import { InjectUtil } from '../../utils/inject-util.js';
import { BuildNativeWithCmake } from '../build-native-with-cmake.js';
import { BuildNativeWithNinja } from '../build-native-with-ninja.js';
import { CacheNativeLibs } from '../cache-native-libs.js';
import { TaskNames } from '../common/task-names.js';
import { ConfigureCmake } from '../configure-cmake.js';
import { DoNativeStrip } from '../do-native-strip.js';
import { PrepareQuickfix } from '../prepare-quickfix.js';
import { ProcessLibs } from '../process-libs.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { TargetTaskCreator, TaskCreatorManager } from '../task-creator.js';

export const initNativeTasks = (creatorManager: TaskCreatorManager, service: TargetTaskService, isFa = false) => {
  creatorManager.registry(new NinjaCA(service, isFa));
  creatorManager.registry(new CmakeCA(service, isFa));
  creatorManager.registry(new ProcessLibsCA(service, isFa));
  creatorManager.registry(new PrepareQuickfixCA(service));
  creatorManager.registry(new DoNativeStripCA(service, isFa));
  creatorManager.registry(new CacheNativeLibsCA(service, isFa));
  creatorManager.registry(new CmakeConfigureCA(service, isFa));
};

export class CmakeCA extends TargetTaskCreator {
  declareDepends = (): string[] => [ConfigureCmake.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.BUILD_NATIVE_WITH_CMAKE;

  provider = () => new BuildNativeWithCmake(this.targetService);
}

export class NinjaCA extends TargetTaskCreator {
  provider = () => new BuildNativeWithNinja(this.targetService);

  declareDepends = (): string[] => {
    CmakeUtil.checkAbiFilters(
      this.targetService.getBuildOption().externalNativeOptions?.abiFilters,
      this.targetService.getTargetData().isHarmonyOS(),
      this.targetService.getModuleService().getModuleModel(),
      this.targetService.getTargetData().getTargetName(),
    );
    const depends: string[] = [BuildNativeWithCmake.name];
    getModuleDependencies(this.targetService, TaskNames.Task.DO_NATIVE_STRIP.name, depends);
    return depends;
  };

  declareTaskDetail = (): TaskDetails => TaskNames.Task.BUILD_NATIVE_WITH_NINJA;
}

export class ProcessLibsCA extends TargetTaskCreator {
  declareDepends = (): string[] => [BuildNativeWithNinja.name];

  declareTaskDetail = (): TaskDetails => TaskNames.Task.PROCESS_LIB;

  provider = () => new ProcessLibs(this.targetService);
}

export class PrepareQuickfixCA extends TargetTaskCreator {
  declareDepends = () => (getPatchConfigMode(this.node.getNodeDir()) === 'hotReload' ? ['ColdReloadArkTS'] : ['ColdReloadArkTS', DoNativeStrip.name]);

  declareTaskDetail = () => TaskNames.Task.PREPARE_QUICKFIX;

  provider = () => new PrepareQuickfix(this.targetService);
}

export class DoNativeStripCA extends TargetTaskCreator {
  declareDepends = () => [ProcessLibs.name];

  declareTaskDetail = () => TaskNames.Task.DO_NATIVE_STRIP;

  provider = () => new DoNativeStrip(this.targetService);
}

export class CacheNativeLibsCA extends TargetTaskCreator {
  declareDepends = () => [TaskNames.Task.DO_NATIVE_STRIP.name];

  declareTaskDetail = () => TaskNames.Task.CACHE_NATIVE_LIBS;

  provider = () => new CacheNativeLibs(this.targetService);
}

export class CmakeConfigureCA extends TargetTaskCreator {
  declareDepends = () => {
    const depends: string[] = [TaskNames.Task.PRE_BUILD.name];
    getModuleDependencies(this.targetService, TaskNames.Task.BUILD_NATIVE_WITH_CMAKE.name, depends);
    return depends;
  };

  declareTaskDetail = () => TaskNames.Task.CONFIGURE_CMAKE;

  provider = () => new ConfigureCmake(this.targetService);
}

function getModuleDependencies(targetService: TargetTaskService, taskName: string, depends: string[]) {
  const depHspTargets = HspTargetUtils.calDepHspTargets(targetService);
  depHspTargets.forEach((target, hspName) => depends.push(`${hspName}:${target.getTargetName()}@${taskName}`));

  const depHarTargets = HarTargetUtil.calDepHarTargets(targetService);
  depHarTargets.forEach((targetName, harName) => depends.push(`${harName}:${targetName}@${taskName}`));

  return depends;
}

/**
 * 得到当前任务是冷重载还是热重载
 * @param modulePath modulePath
 */
function getPatchConfigMode(modulePath: string) {
  const moduleBuildPath = path.resolve(
    InjectUtil.getBuildCacheParentDir(
      modulePath,
      // Safety: hvigor.getProject()必然已经被初始化
      path.join(hvigorCore.getProject()!.getName(), modulePath.substring(hvigorCore.getProject()!.getNodeDir().length)),
      true,
    ),
    'build',
  );
  const moduleBuildConfigPath = path.resolve(moduleBuildPath, 'config', 'buildConfig.json');
  if (fse.existsSync(moduleBuildConfigPath)) {
    const buildConfig = fse.readJsonSync(moduleBuildConfigPath);
    return buildConfig?.patchConfig?.mode;
  }
  return undefined;
}
